/* Copyright (c) 2024 Huawei Technologies Co., Ltd.
* This file is a part of the CANN Open Software.
* Licensed under CANN Open Software License Agreement Version 1.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
* ===================================================================================================================*/

#include <gtest/gtest.h>
#include <symengine/integer.h>
#include <symengine/assumptions.h>
#include <symengine/functions.h>
#include <symengine/simplify.h>
#include <symengine/real_double.h>
#include <iostream>
#include <cmath>

#define private public
#define protected public
#include "graph/symbolic.h"
#include "expression/expression_impl.h"
#undef protected
#undef private

namespace ge {
class UtestExpression : public testing::Test {
 protected:
  void SetUp() {}

  void TearDown() {}
};
using namespace ge;
using namespace ge::sym;

TEST_F(UtestExpression, TestBasic) {
  auto symbol2 = Symbol(2);
  EXPECT_EQ(symbol2, 2);
  auto symbol4 = Symbol(4);
  EXPECT_EQ(symbol4, 4);
  EXPECT_EQ(symbol2 + symbol4, 6);
  EXPECT_EQ(symbol4 - symbol2, 2);
  EXPECT_EQ(symbol4 * symbol2, 8);
  EXPECT_EQ(symbol4 / symbol2, 2);

  auto e2 = Expression(symbol2);
  EXPECT_EQ(e2, 2);
  Expression copy_e2;
  copy_e2 = e2;
  EXPECT_EQ(copy_e2, 2);
  auto e4 = Expression(symbol4);
  EXPECT_EQ(e4, 4);
  EXPECT_EQ(e2 + e4, 6);
  EXPECT_EQ(e4 - e2, 2);
  EXPECT_EQ(e4 * e2, 8);
  EXPECT_EQ(e4 / e2, 2);
}

TEST_F(UtestExpression, GetExprType) {
  auto symbol1 = Symbol(2);
  EXPECT_EQ(symbol1, 2);
  EXPECT_NE(symbol1, 3);

  auto symbol2 = Symbol(2.0);
  EXPECT_EQ(symbol2, 2.0);
  EXPECT_NE(symbol2, 2);

  EXPECT_EQ(symbol1.GetExprType(), ExprType::kExprConstantInteger);

  auto symbol_uint32 = Symbol(2);
  EXPECT_EQ(symbol_uint32.GetExprType(), ExprType::kExprConstantInteger);

  auto symbol_int64 = Symbol(2l);
  EXPECT_EQ(symbol_int64.GetExprType(), ExprType::kExprConstantInteger);

  auto symbol_uint64 = Symbol(2lu);
  EXPECT_EQ(symbol_uint64.GetExprType(), ExprType::kExprConstantInteger);

  auto symbol_double = Symbol(2.5);
  EXPECT_EQ(symbol_double.GetExprType(), ExprType::kExprConstantRealDouble);

  auto symbol_num = Symbol(2);
  auto symbol_den = Symbol(3);
  auto ret = Div(symbol_num, symbol_den);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprConstantRation);

  ret = Mul(symbol_num, symbol_den);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprConstantInteger);

  ret = Add(symbol_num, symbol_den);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprConstantInteger);

  ret = Sub(symbol_num, symbol_den);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprConstantInteger);

  ret = Max(symbol_num, symbol_den);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprConstantInteger);

  ret = Min(symbol_num, symbol_den);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprConstantInteger);

  ret = Ceiling(symbol_double);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprConstantInteger);

  ret = Pow(symbol_num, symbol_den);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprConstantInteger);

  ret = Log(symbol_num, symbol_den);
  EXPECT_EQ(ret.GetExprType(), ExprType::kExprOperation);

  symbol2 = Symbol("a");
  EXPECT_EQ(symbol2.GetExprType(), ExprType::kExprVariable);

  auto expr3 = Add(symbol1, symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);
  EXPECT_NE(expr3, symbol2);

  expr3 = Sub(symbol1, symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Mul(symbol1, symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Div(symbol1, symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Max(symbol1, symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Min(symbol1, symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Pow(symbol1, symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Abs(symbol1);  // symbol1是常量
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprConstantInteger);

  expr3 = Abs(symbol2);  // symbol2是符号
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Log(symbol1, symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Log(symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Ceiling(symbol2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);

  expr3 = Rational(1, 2);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprConstantRation);

  auto symbol_x = Symbol("x");
  auto symbol_2 = Symbol(2);
  auto symbol_n = Symbol(1);
  auto symbol = Mul(symbol_x, symbol_2);
  expr3 = Coeff(symbol, symbol_x, symbol_n);
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprConstantInteger);
  EXPECT_EQ(expr3, 2);

  // 3*x**2 + 2*x*y + 1
  auto expr_coeff_base =
      Add(Add(Mul(Symbol(3), Pow(Symbol("x"), Symbol(2))), Mul(Mul(Symbol(2), Symbol("x")), Symbol("y"))), Symbol(1));
  expr3 = Coeff(expr_coeff_base, Symbol("x"), Symbol(2));
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprConstantInteger);
  EXPECT_EQ(expr3, 3);

  expr3 = Coeff(expr_coeff_base, Symbol("x"), Symbol(1));
  EXPECT_EQ(expr3.GetExprType(), ExprType::kExprOperation);
  EXPECT_EQ(std::string(expr3.Str().get()), "(2 * y)");
}

TEST_F(UtestExpression, Str) {
  auto var_b = Symbol("b");
  auto var_c = Symbol("c");
  auto b_div_c = Div(var_b, var_c);
  EXPECT_EQ(std::string(b_div_c.Str().get()), "(b / (c))");
  auto one = Symbol(1);
  auto b_div_one = Div(one, var_c);
  EXPECT_EQ(std::string(b_div_one.Str().get()), "Pow(c, -1)");

  auto b_max_c = Max(b_div_c, var_c);
  EXPECT_EQ(std::string(b_max_c.Str().get()), "Max(c, (b / (c)))");


//  EXPECT_EQ(Rational(2, 3)->Str(), "(double)(2)/(double)(3)");
  EXPECT_EQ(std::string(Pow(var_b, Rational(1, 2)).Str().get()), "Sqrt(b)");
  EXPECT_EQ(std::string(Pow(var_b, Symbol(3)).Str().get()), "(b * b * b)");
  EXPECT_EQ(std::string(Pow(var_b, var_c).Str().get()), "Pow(b, c)");
  EXPECT_EQ(std::string(Ceiling(var_b).Str().get()), "Ceiling(b)");
  EXPECT_EQ(std::string(Abs(var_b).Str().get()), "Abs(b)");
  EXPECT_EQ(std::string(Sub(Symbol(2), Symbol(3) * var_b).Str().get()), "(2 - (3 * b))");
  EXPECT_EQ(std::string(Max(Max(var_b, var_c), Symbol("d")).Str().get()),
    "Max(Max(b, c), d)");
  EXPECT_EQ(std::string(Min(Min(var_b, var_c), Symbol("d")).Str().get()),
    "Min(Min(b, c), d)");
}

TEST_F(UtestExpression, Parser) {
  auto var_b = Symbol("b");
  auto var_c = Symbol("c");
  auto b_div_c = Div(var_b, var_c);
  EXPECT_EQ(std::string(b_div_c.Str().get()), "(b / (c))");
  auto b_div_parser = Expression::Parse(b_div_c.Str().get());
  EXPECT_EQ(b_div_c, b_div_parser);
  auto b_max_c = Max(b_div_c, var_c);
  EXPECT_EQ(std::string(b_max_c.Str().get()), "Max(c, (b / (c)))");

  auto double_2_3 = Rational(2, 3);
  EXPECT_EQ(std::string(double_2_3.Str().get()), "Rational(2 , 3)");
  auto double_2_3_parser = Expression::Parse(double_2_3.Str().get());
  // todo: 对于表达式2/3，当前的序列化为了给c++编译器编译，搞成了(double)(2)/(double)(3)，是一个Rational
  //       本次修改为采用Rational(a, b)表达的方式，来表达分子分母，当前只支持int类型的分子分母，给c++编译时，写一个Rational函数，
  //       函数里面做double的cast转换
  EXPECT_EQ(double_2_3_parser, double_2_3);

  auto pow_3 = Pow(var_b, Symbol(3));
  EXPECT_EQ(std::string(pow_3.Str().get()), "(b * b * b)");
  auto power_parser_3 = Expression::Parse(pow_3.Str().get());
  EXPECT_EQ(power_parser_3, pow_3);

  auto pow_b_c = Pow(var_b, var_c);
  EXPECT_EQ(std::string(pow_b_c.Str().get()), "Pow(b, c)");
  auto power_parser_b_c = Expression::Parse(pow_b_c.Str().get());
  EXPECT_EQ(power_parser_b_c, pow_b_c);

  auto log_b_c = Log(var_b, var_c);
  EXPECT_EQ(std::string(log_b_c.Str().get()), "(Log(b) / (Log(c)))");
  auto log_parser_b_c = Expression::Parse(log_b_c.Str().get());
  EXPECT_EQ(log_parser_b_c, log_b_c);

  auto sub_mul = Sub(Symbol(2), Symbol(3) * var_b);
  EXPECT_EQ(std::string(sub_mul.Str().get()), "(2 - (3 * b))");
  auto sub_mul_parser = Expression::Parse(sub_mul.Str().get());
  EXPECT_EQ(sub_mul_parser, sub_mul);

  auto add_mul = Add(Symbol(2), Symbol(3) * var_b);
  EXPECT_EQ(std::string(add_mul.Str().get()), "((3 * b) + 2)");  // 不保证顺序
  auto add_mul_parser = Expression::Parse(add_mul.Str().get());
  EXPECT_EQ(add_mul_parser, add_mul);

  auto max_max = Max(Max(var_b, var_c), Symbol("d"));
  EXPECT_EQ(std::string(max_max.Str().get()), "Max(Max(b, c), d)");
  auto max_max_parser = Expression::Parse(max_max.Str().get());
  EXPECT_EQ(max_max_parser, max_max);

  auto min_min = Min(Min(var_b, var_c), Symbol("d"));
  EXPECT_EQ(std::string(min_min.Str().get()), "Min(Min(b, c), d)");
  auto min_min_parser = Expression::Parse(min_min.Str().get());
  EXPECT_EQ(min_min_parser, min_min);

  // 这个地方主线的序列化不保序，按照主线处理
  auto min_max = Min(Max(var_b, var_c), Symbol("d"));
  EXPECT_EQ(std::string(min_max.Str().get()), "Min(d, Max(b, c))");
  auto min_max_parser = Expression::Parse(min_max.Str().get());
  EXPECT_EQ(min_max_parser, min_max);

  auto ceil = Ceiling(var_b);
  EXPECT_EQ(std::string(ceil.Str().get()), "Ceiling(b)");
  auto ceil_parser = Expression::Parse(ceil.Str().get());
  EXPECT_EQ(ceil_parser, ceil);

  auto abs = Abs(var_b);
  EXPECT_EQ(std::string(abs.Str().get()), "Abs(b)");
  auto abs_parser = Expression::Parse(abs.Str().get());
  EXPECT_EQ(abs_parser, abs);

  auto min_5_double = Min(Max(var_b, var_c), Symbol(5.0));
  EXPECT_EQ(std::string(min_5_double.Str().get()), "Min(Max(b, c), 5.0)");
  auto min_5_double_parser = Expression::Parse(min_5_double.Str().get());
  EXPECT_EQ(min_5_double_parser, min_5_double);

  EXPECT_EQ(std::string(var_b.GetName().get()), "b");
}

TEST_F(UtestExpression, Parser_Invalid) {
  auto failed_parser = Expression::Parse("1 % dsfde )");
  EXPECT_EQ(failed_parser.IsValid(), false);

  failed_parser = Expression::Parse("5* (sincos(s0s1))");
  EXPECT_EQ(failed_parser.IsValid(), false);
}

TEST_F(UtestExpression, Serialize_And_Deserialize) {
  auto var_b = Symbol("b");
  auto var_c = Symbol("c");
  auto b_div_c = Div(var_b, var_c);
  EXPECT_EQ(std::string(b_div_c.Serialize().get()), "(b / (c))");
  auto b_div_parser = Expression::Deserialize(b_div_c.Str().get());
  EXPECT_EQ(b_div_c, b_div_parser);
  auto b_max_c = Max(b_div_c, var_c);
  EXPECT_EQ(std::string(b_max_c.Serialize().get()), "Max(c, (b / (c)))");

  auto double_2_3 = Rational(2, 3);
  EXPECT_EQ(std::string(double_2_3.Serialize().get()), "Rational(2 , 3)");
  auto double_2_3_parser = Expression::Deserialize(double_2_3.Str().get());
  // todo: 对于表达式2/3，当前的序列化为了给c++编译器编译，搞成了(double)(2)/(double)(3)，是一个Rational
  //       本次修改为采用Rational(a, b)表达的方式，来表达分子分母，当前只支持int类型的分子分母，给c++编译时，写一个Rational函数，
  //       函数里面做double的cast转换
  EXPECT_EQ(double_2_3_parser, double_2_3);

  auto pow_3 = Pow(var_b, Symbol(3));
  EXPECT_EQ(std::string(pow_3.Serialize().get()), "(b * b * b)");
  auto power_parser_3 = Expression::Deserialize(pow_3.Str().get());
  EXPECT_EQ(power_parser_3, pow_3);

  auto pow_b_c = Pow(var_b, var_c);
  EXPECT_EQ(std::string(pow_b_c.Serialize().get()), "Pow(b, c)");
  auto power_parser_b_c = Expression::Deserialize(pow_b_c.Str().get());
  EXPECT_EQ(power_parser_b_c, pow_b_c);

  auto log_b_c = Log(var_b, var_c);
  EXPECT_EQ(std::string(log_b_c.Serialize().get()), "(Log(b) / (Log(c)))");
  auto log_parser_b_c = Expression::Deserialize(log_b_c.Str().get());
  EXPECT_EQ(log_parser_b_c, log_b_c);

  auto sub_mul = Sub(Symbol(2), Symbol(3) * var_b);
  EXPECT_EQ(std::string(sub_mul.Serialize().get()), "(2 - (3 * b))");
  auto sub_mul_parser = Expression::Deserialize(sub_mul.Str().get());
  EXPECT_EQ(sub_mul_parser, sub_mul);

  auto add_mul = Add(Symbol(2), Symbol(3) * var_b);
  EXPECT_EQ(std::string(add_mul.Serialize().get()), "((3 * b) + 2)");  // 不保证顺序
  auto add_mul_parser = Expression::Deserialize(add_mul.Str().get());
  EXPECT_EQ(add_mul_parser, add_mul);

  auto max_max = Max(Max(var_b, var_c), Symbol("d"));
  EXPECT_EQ(std::string(max_max.Serialize().get()), "Max(Max(b, c), d)");
  auto max_max_parser = Expression::Deserialize(max_max.Serialize().get());
  EXPECT_EQ(max_max_parser, max_max);

  auto min_min = Min(Min(var_b, var_c), Symbol("d"));
  EXPECT_EQ(std::string(min_min.Serialize().get()), "Min(Min(b, c), d)");
  auto min_min_parser = Expression::Deserialize(min_min.Serialize().get());
  EXPECT_EQ(min_min_parser, min_min);

  // 这个地方主线的序列化不保序，按照主线处理
  auto min_max = Min(Max(var_b, var_c), Symbol("d"));
  EXPECT_EQ(std::string(min_max.Serialize().get()), "Min(d, Max(b, c))");
  auto min_max_parser = Expression::Deserialize(min_max.Serialize().get());
  EXPECT_EQ(min_max_parser, min_max);

  auto ceil = Ceiling(var_b);
  EXPECT_EQ(std::string(ceil.Serialize().get()), "Ceiling(b)");
  auto ceil_parser = Expression::Deserialize(ceil.Serialize().get());
  EXPECT_EQ(ceil_parser, ceil);

  auto abs = Abs(var_b);
  EXPECT_EQ(std::string(abs.Serialize().get()), "Abs(b)");
  auto abs_parser = Expression::Deserialize(abs.Serialize().get());
  EXPECT_EQ(abs_parser, abs);

  auto min_5_double = Min(Max(var_b, var_c), Symbol(5.0));
  EXPECT_EQ(std::string(min_5_double.Serialize().get()), "Min(Max(b, c), 5.0)");
  auto min_5_double_parser = Expression::Deserialize(min_5_double.Serialize().get());
  EXPECT_EQ(min_5_double_parser, min_5_double);

  EXPECT_EQ(std::string(var_b.GetName().get()), "b");
}

// 如果不是按照序列化出来的字符串去进行反序列化，反序列化会失败
TEST_F(UtestExpression, Deserialize_Invalid) {
  auto failed_parser = Expression::Deserialize("s0*s1");
  EXPECT_EQ(failed_parser.IsValid(), false);

  failed_parser = Expression::Deserialize("a+2");
  EXPECT_EQ(failed_parser.IsValid(), false);
}

TEST_F(UtestExpression, EqualAndNotEqual) {
  auto var_b = Symbol("b");
  auto int_2 = Symbol(2);
  auto int_3 = Symbol(3);
  auto int_n_6 = Symbol(-6);
  auto int_6 = Symbol(6);

  auto b_2 = Mul(var_b, int_2);
  auto b_b = Add(var_b, var_b);
  EXPECT_TRUE(b_2 == b_b);

  auto b_3 = Mul(var_b, int_3);
  EXPECT_TRUE(b_3 != b_b);

  auto abs_1 = Abs(int_n_6);
  EXPECT_TRUE(abs_1 == int_6);
}

TEST_F(UtestExpression, GetName) {
  auto var_b = Symbol("b");
  EXPECT_EQ(std::string(var_b.GetName().get()), "b");
  auto var_c = Symbol(static_cast<int32_t>(1), "s0");
  EXPECT_EQ(std::string(var_c.GetName().get()), "s0");
  auto var_d = Symbol(static_cast<int64_t>(1), "s1");
  EXPECT_EQ(std::string(var_d.GetName().get()), "s1");
  auto var_e = Symbol(static_cast<uint32_t>(1), "s2");
  EXPECT_EQ(std::string(var_e.GetName().get()), "s2");
  auto var_f = Symbol(static_cast<uint64_t>(1), "s3");
  EXPECT_EQ(std::string(var_f.GetName().get()), "s3");
  auto var_g = Symbol(static_cast<double>(1.0), "s4");
  EXPECT_EQ(std::string(var_g.GetName().get()), "s4");
  auto var_h = Symbol(static_cast<double>(1.0));
  EXPECT_EQ(std::string(var_h.GetName().get()), "Const_0");
  auto var_i = Symbol(static_cast<int32_t>(5));
  EXPECT_EQ(std::string(var_i.GetName().get()), "Const_1");
}

TEST_F(UtestExpression, Operator) {
  auto var_b = Symbol("b");
  auto var_c = Symbol("c");
  EXPECT_EQ((var_b + var_c).GetExprType(), ExprType::kExprOperation);
  EXPECT_EQ((var_b - var_c).GetExprType(), ExprType::kExprOperation);
  EXPECT_EQ((var_b * var_c).GetExprType(), ExprType::kExprOperation);
  EXPECT_EQ((var_b / var_c).GetExprType(), ExprType::kExprOperation);
}

TEST_F(UtestExpression, Replace) {
  auto var_b = Symbol("b");
  auto var_c = Symbol("c");
  auto var_d = Symbol("d");
  auto b_div_c = Div(var_b, var_c);
  std::vector<std::pair<Expression, Expression>> replace_vars;
  replace_vars.push_back({var_b, var_d});
  auto replace_expr = b_div_c.Replace(replace_vars);
  EXPECT_TRUE(replace_expr == Div(var_d, var_c));
}

TEST_F(UtestExpression, Subs) {
  auto var_b = Symbol("b");
  auto var_c = Symbol("c");
  auto var_d = Symbol("d");
  auto b_div_c = Div(var_b, var_c);
  std::vector<std::pair<Expression, Expression>> subs_vars;
  subs_vars.push_back({var_b, var_d});
  auto subs_expr = b_div_c.Subs(subs_vars);
  EXPECT_TRUE(subs_expr == Div(var_d, var_c));
}

TEST_F(UtestExpression, Simplify) {
  auto var_b = Symbol("b");
  auto const_1 = Symbol(1);
  auto const_2 = Symbol(2);
  auto const_3 = Symbol(3);
  EXPECT_TRUE((Add(Add(var_b, const_1), const_2).Simplify()) == Add(var_b, const_3));
}

TEST_F(UtestExpression, GetPrimaryArgs) {
  auto const_neg_2 = Symbol(-2);
  auto const_neg_3 = Symbol(-3);
  auto var_b = Symbol("b");
  auto var_c = Symbol("c");
  auto var_d = Symbol("d");
  auto var_e = Symbol("e");
  std::vector<Expression> args_exp = {var_b, var_c, var_d, var_e};
  auto mul_expr = Min(Max(Add(Pow(Mul(const_neg_2, var_b), Mul(var_b, const_neg_3)), var_c), var_d), var_e);
  auto prim_args = mul_expr.FreeSymbols();
  EXPECT_EQ(prim_args.size(), args_exp.size());
  bool has_find = true;
  for (auto &arg_get : prim_args) {
    bool one_has_find = false;
    for (auto &arg_exp : args_exp) {
      if (arg_get == arg_exp) {
        one_has_find = true;
        break;
      }
    }
    if (!one_has_find) {
      has_find = false;
      break;
    }
  }
  EXPECT_EQ(has_find, true);
}

TEST_F(UtestExpression, ContainVar) {
  auto var_b = Symbol("b");
  auto const_1 = Symbol(1);
  EXPECT_TRUE(Add(var_b, const_1).ContainVar(var_b));
  EXPECT_FALSE(Add(var_b, const_1).ContainVar(const_1));
}

TEST_F(UtestExpression, GetResult) {
  auto var_b = Symbol("b");
  auto var_c = Symbol("c");
  auto b_add_c = Add(var_b, var_c);
  std::vector<std::pair<Expression, Expression>> replace_vars;
  replace_vars.emplace_back(var_b, Symbol(1));
  replace_vars.emplace_back(var_c, Symbol(2));
  double result;
  auto code = b_add_c.GetResult(replace_vars, result);
  EXPECT_EQ(code, ge::GRAPH_SUCCESS);
  EXPECT_EQ(result, static_cast<double>(3));

  replace_vars.clear();
  replace_vars.emplace_back(var_b, Symbol(1.0));
  replace_vars.emplace_back(var_c, Symbol(2.0));
  code = b_add_c.GetResult(replace_vars, result);
  EXPECT_EQ(code, ge::GRAPH_SUCCESS);
  EXPECT_EQ(result, static_cast<double>(3));

  replace_vars.clear();
  replace_vars.emplace_back(var_b, Symbol(1));
  replace_vars.emplace_back(var_c, Rational(2, 3));
  code = b_add_c.GetResult(replace_vars, result);
  EXPECT_EQ(code, ge::GRAPH_SUCCESS);
  EXPECT_TRUE(std::abs(result - (static_cast<double>(1) + static_cast<double>(2) / static_cast<double>(3))) < 0.0001);
}

TEST_F(UtestExpression, TestInvalid) {
  Expression expr;
  expr.impl_ = nullptr;
  EXPECT_EQ(expr.IsValid(), false);
  EXPECT_EQ(expr.Str(), nullptr);
  EXPECT_EQ(expr.GetExprType(), ExprType::kExprNone);
  double tmp = 1.0;
  EXPECT_EQ(expr.GetResult({}, tmp), GRAPH_FAILED);
  Expression tmp_expr;
  EXPECT_EQ(expr.ContainVar(tmp_expr), false);
  EXPECT_EQ(expr.Subs({}).IsValid(), false);
  EXPECT_EQ(expr.Simplify().IsValid(), false);
  EXPECT_EQ(expr.FreeSymbols().size(), 0);

  Symbol symbol_1(1, "one");
  symbol_1.impl_ = nullptr;
  EXPECT_EQ(symbol_1.IsValid(), false);
  EXPECT_EQ(symbol_1.GetName(), nullptr);
}

TEST_F(UtestExpression, GetConstValue) {
  auto var_b = Symbol("b");
  int32_t value;
  EXPECT_EQ(var_b.GetConstValue<int32_t>(value), false);

  int32_t value1 = 2;
  auto const_1 = Symbol(value1);
  int32_t res_value1;
  EXPECT_EQ(const_1.GetConstValue<int32_t>(res_value1), true);
  EXPECT_EQ(res_value1, value1);

  uint32_t value2 = 1;
  auto const_2 = Symbol(value2);
  uint32_t res_value2;
  EXPECT_EQ(const_2.GetConstValue<uint32_t>(res_value2), true);
  EXPECT_EQ(res_value2, value2);

  double value3 = 1.0;
  auto const_3 = Symbol(value3);
  double res_value3;
  EXPECT_EQ(const_3.GetConstValue<double>(res_value3), true);
  EXPECT_EQ(res_value3, value3);

  float value4 = 1.0;
  auto const_4 = Symbol(value4);
  float res_value4;
  EXPECT_EQ(const_4.GetConstValue<float>(res_value4), true);
  EXPECT_EQ(res_value4, value4);

  int64_t value5 = 1;
  auto const_5 = Symbol(value5);
  int64_t res_value5;
  EXPECT_EQ(const_5.GetConstValue<int64_t>(res_value5), true);
  EXPECT_EQ(res_value5, value5);

  uint64_t value6 = 1;
  auto const_6 = Symbol(value6);
  uint64_t res_value6;
  EXPECT_EQ(const_6.GetConstValue<uint64_t>(res_value6), true);
  EXPECT_EQ(res_value6, value6);

  // 常量 + 常量
  auto add = sym::Add(const_6, const_6);
  uint64_t res_value7;
  EXPECT_EQ(add.GetConstValue<uint64_t>(res_value7), true);
  EXPECT_EQ(res_value7, value6 + value6);

  // 常量 * 常量
  auto mul = sym::Mul(const_6, const_6);
  uint64_t res_value8;
  EXPECT_EQ(mul.GetConstValue<uint64_t>(res_value8), true);
  EXPECT_EQ(res_value8, value6 * value6);

  // 常量 - 常量
  auto sub = sym::Sub(const_6, const_6);
  uint64_t res_value9;
  EXPECT_EQ(sub.GetConstValue<uint64_t>(res_value9), true);
  EXPECT_EQ(res_value9, value6 - value6);

  // 常量 / 常量
  auto div = sym::Div(const_6, const_6);
  uint64_t res_value10;
  EXPECT_EQ(div.GetConstValue<uint64_t>(res_value10), true);
  EXPECT_EQ(res_value10, value6 / value6);

  // Max(常量, 常量)
  auto max1 = sym::Max(const_1, const_6);
  uint64_t res_value11;
  EXPECT_EQ(max1.GetConstValue<uint64_t>(res_value11), true);
  EXPECT_EQ(res_value11, std::max(static_cast<uint64_t>(value1), value6));

  // 常量 + 变量
  auto add20 = sym::Add(const_6, var_b);
  uint64_t res_value20;
  EXPECT_EQ(add20.GetConstValue<uint64_t>(res_value20), false);

  // 常量绝对值 -> 常量
  auto abs1 = sym::Abs(const_6);
  uint64_t res_value21;
  EXPECT_EQ(abs1.GetConstValue<uint64_t>(res_value21), true);

  // 变量绝对值 -> 变量
  auto abs2 = sym::Abs(var_b);
  uint64_t res_value22;
  EXPECT_EQ(abs2.GetConstValue<uint64_t>(res_value22), false);
}

TEST_F(UtestExpression, TestAlgin) {
  auto s0 = Symbol("s0");
  auto s1 = Symbol("s1");

  auto expr1 = Align(s0, 32);
  auto expr2 = Align(s0, 32);
  EXPECT_EQ(expr1, expr2);

  auto str = expr1.Str();
  EXPECT_EQ(std::string(str.get()), "(32 * Ceiling((Rational(1 , 32) * s0)))");
  auto expr3 = Expression::Parse(str.get());
  EXPECT_EQ(expr1, expr3);

  auto const_16 = Symbol(32);
  auto const_1 = Symbol(1);
  auto expr4 = (const_16 * Ceiling((Rational(1 , 32) * s0)));
  EXPECT_EQ(expr1, expr4);
}
} // namespace ge
